/*M///////////////////////////////////////////////////////////////////////////////////////
 //
 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 //
 //  By downloading, copying, installing or using the software you agree to this license.
 //  If you do not agree to this license, do not download, install,
 //  copy or use the software.
 //
 //
 //                           License Agreement
 //                For Open Source Computer Vision Library
 //
 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
 // Copyright (C) 2009-2010, Willow Garage Inc., all rights reserved.
 // Third party copyrights are property of their respective owners.
 //
 // Redistribution and use in source and binary forms, with or without modification,
 // are permitted provided that the following conditions are met:
 //
 //   * Redistribution's of source code must retain the above copyright notice,
 //     this list of conditions and the following disclaimer.
 //
 //   * Redistribution's in binary form must reproduce the above copyright notice,
 //     this list of conditions and the following disclaimer in the documentation
 //     and/or other materials provided with the distribution.
 //
 //   * The name of the copyright holders may not be used to endorse or promote products
 //     derived from this software without specific prior written permission.
 //
 // This software is provided by the copyright holders and contributors "as is" and
 // any express or implied warranties, including, but not limited to, the implied
 // warranties of merchantability and fitness for a particular purpose are disclaimed.
 // In no event shall the Intel Corporation or contributors be liable for any direct,
 // indirect, incidental, special, exemplary, or consequential damages
 // (including, but not limited to, procurement of substitute goods or services;
 // loss of use, data, or profits; or business interruption) however caused
 // and on any theory of liability, whether in contract, strict liability,
 // or tort (including negligence or otherwise) arising in any way out of
 // the use of this software, even if advised of the possibility of such damage.
 //
 //M*/

#include "BRIEF.h"
#include <algorithm>
#include <vector>

#include <iostream>
#include <iomanip>

using namespace cv;
namespace markerAR
{
    
inline int smoothedSum(const Mat& sum, const Eigen::Vector2d& pt, int y, int x)
{
    static const int HALF_KERNEL = BriefDescriptorExtractor::KERNEL_SIZE / 2;
    
    int img_y = (int)(pt.y() + 0.5) + y;
    int img_x = (int)(pt.x() + 0.5) + x;
    return   sum.ptr<int>(img_y + HALF_KERNEL + 1)[img_x + HALF_KERNEL + 1]
    - sum.ptr<int>(img_y + HALF_KERNEL + 1)[img_x - HALF_KERNEL]
    - sum.ptr<int>(img_y - HALF_KERNEL)[img_x + HALF_KERNEL + 1]
    + sum.ptr<int>(img_y - HALF_KERNEL)[img_x - HALF_KERNEL];
}


static void pixelTests32(const Mat& sum, std::vector<Feature*>& fts)
{
    for (int i = 0; i < fts.size(); ++i)
    {
        if (fts[i]->isBad()) {
            continue;
        }
        uchar* desc = fts[i]->desp.ptr();
        const Eigen::Vector2d& pt = fts[i]->_pos;
#include "generated_32.i"
    }
}

void BRIEF::computeImpl(const Mat& image, std::vector<Feature*>& fts) const
{
    // Construct integral image for fast smoothing (box filter)
    Mat sum;
    
    Mat grayImage = image;
    if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
    
    ///TODO allow the user to pass in a precomputed integral image
    //if(image.type() == CV_32S)
    //  sum = image;
    //else
    
    integral( grayImage, sum, CV_32S);
    
    pixelTests32(sum, fts);
}








BRIEF::BRIEF(int threshold,int npoints)
{
    fd = FastWrapper(threshold);
    //    anms = ANMS(imgSize);
    binaryMatcher = DescriptorMatcher::create("BruteForce-Hamming");
    this->npoints = npoints;
    this->imgSize = imgSize;
}

BRIEF::~BRIEF()
{
}

void BRIEF::operator()(const Mat&img,const Mat&mask,std::vector<Feature*>&fts)
{
    detect(img, fts,mask);
    compute(img, fts);
    
}
void BRIEF::operator()(const Mat&img,const Mat&mask,std::vector<KeyPoint>&kpts,cv::Mat&desp)
{
    detect(img, kpts, npoints, mask);
    extractor.compute(img, kpts, desp);
}

void BRIEF::detect(const Mat&img, vector<KeyPoint>&kpts, const Mat&mask)
{
    detect(img, kpts, npoints, mask);
}

void BRIEF::compute(const Mat&img,vector<KeyPoint>&kpts, Mat &desp)
{
    extractor.compute(img, kpts, desp);
}

void BRIEF::compute(const Mat&img, vector<Feature*>&fts) const
{
    const int border = 48 / 2 + 9 / 2;
    const int maxRow = img.rows - border;
    const int maxCol = img.cols - border;
    //check whether the feature is out of range
    for (int i=0; i<fts.size(); ++i) {
        if (fts[i]->_pos(0)<border||fts[i]->_pos(0)>maxCol||fts[i]->_pos(1)<border||fts[i]->_pos(1)>maxRow) {
            fts[i]->isBad() = true;
        }
        if(fts[i]->desp.empty())
            fts[i]->desp = cv::Mat(1,32,CV_8U);
    }
    computeImpl(img, fts);
    
}

void BRIEF::detect(const Mat&img, vector<Feature*>&fts, const Mat&mask)
{
    const int border = 48 / 2 + 9 / 2;
    fd.detect(img, fts, mask,npoints,border);
    for (int i=0; i<fts.size(); ++i) {
        fts[i]->sigma = 1.0f;
    }
}

void BRIEF::detect(const Mat&img, vector<KeyPoint>&kpts, const int npoints, const Mat&mask)
{
    const int border = 48 / 2 + 9 / 2;
    fd.detect(img, kpts, mask,npoints,border);
}

void BRIEF::knnMatch(const Mat&queryDesp, const Mat&trainDesp, vector<vector<DMatch>> &dmatches,int k)
{
    binaryMatcher->knnMatch(queryDesp, trainDesp,dmatches,k);
}

void BRIEF::detect(const vector<Mat>&allImgs, vector<vector<Feature*>>&allKpts, int npoints,float scale, int levelNum)
{
    float sum=0;
    vector<float> allScale(levelNum);
    for (size_t i = 0; i < levelNum; i++)
    {
        allScale[i] = 1 / pow(scale, i);
        sum += allScale[i];
    }
    
    for (size_t i = 0; i < allImgs.size(); i++)
    {
        float sigma = pow(scale,i);
        auto &img = allImgs[i];
        auto &kpts = allKpts[i];
        detect(img, kpts);
        for (int i=0; i<kpts.size(); ++i) {
            kpts[i]->sigma = sigma;
        }
    }
}

void BRIEF::compute(const vector<Mat>&allImgs, vector<vector<Feature*>>&allKpts)
{
    for (int i=0;i<allImgs.size(); ++i) {
        compute(allImgs[i], allKpts[i]);
    }
}

void BRIEF::detect(const vector<Mat>&allImgs, vector<vector<KeyPoint>>&allKpts, int npoints,float scale, int levelNum)
{
    float sum=0;
    vector<float> allScale(levelNum);
    for (size_t i = 0; i < levelNum; i++)
    {
        allScale[i] = 1 / pow(scale, i);
        sum += allScale[i];
    }
    
    for (size_t i = 0; i < allImgs.size(); i++)
    {
        int n;
        n = npoints*allScale[i] / sum;
        auto &img = allImgs[i];
        auto &kpts = allKpts[i];
        detect(img, kpts,npoints);
    }
}



void BRIEF::compute(const vector<Mat>&allImgs, vector<vector<KeyPoint>>&allKpts, vector<Mat> &allDesps)
{
    for (size_t i = 0; i < allImgs.size(); i++)
    {
        auto &img = allImgs[i];
        auto &kpts = allKpts[i];
        auto &desp = allDesps[i];
        compute(img, kpts, desp);
    }
}
}

